package com.huike.springboot1.demos.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    // 注入自定义用户详情服务（查询用户信息）
    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    // 注入自定义权限元数据源（获取URL所需权限）
    @Autowired
    private CustomFilterInvocationSecurityMetadataSource securityMetadataSource;

    // 注入自定义权限决策管理器（判断用户是否有权限访问）
    @Autowired
    private CustomUrlDecisionManager urlDecisionManager;

    // 密码加密器（BCrypt算法）
    @Bean
    public PasswordEncoder passwordEncoder() {
//        return new BCryptPasswordEncoder();//加密密码
        return NoOpPasswordEncoder.getInstance();//明文密码
    }

    // 配置静态资源放行（不经过Security过滤器链）
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/css/**", "/js/**", "/images/**"); // 静态资源路径，根据实际项目调整
    }

    // 核心安全配置（URL拦截、登录、权限控制等）
    @Override
    protected void configure(HttpSecurity http) throws Exception {


        // 2. 配置URL访问权限
        http.authorizeRequests()
                // 放行登录页、登录提交路径（必须放行，否则无法访问登录页），也要通行查询路径，否则会下方显示登录页内容
                .antMatchers("/toLogin", "/login","/check","/register", "/sendCode", "/doRegister").permitAll()
                // 其他所有请求必须认证（登录后才能访问）
                .anyRequest().authenticated()
                // 3. 绑定自定义权限控制（URL权限匹配+决策）
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        // 设置权限元数据源（URL→所需权限的映射）
                        object.setSecurityMetadataSource(securityMetadataSource);
                        // 设置权限决策管理器（判断用户是否有权限）
                        object.setAccessDecisionManager(urlDecisionManager);
                        return object;
                    }
                })
                .and()

                // 4. 配置表单登录（自定义登录页和提交路径）
                .formLogin()
                .loginPage("/toLogin") // 登录页路径（未登录时自动跳转这里）
                .loginProcessingUrl("/login") // 登录提交路径（表单action指向此路径）
                .defaultSuccessUrl("/check", true) // 登录成功后跳转的页面（第二个参数true表示强制跳转）
                .failureUrl("/toLogin?error") // 登录失败后跳转的页面（带错误参数）
                .usernameParameter("username") // 登录账号参数名（与表单name一致）
                .passwordParameter("password") // 登录密码参数名（与表单name一致）
                .permitAll() // 允许所有用户访问登录相关路径
                .and()

                // 5. 配置注销功能
                .logout()
                .logoutUrl("/logout") // 注销请求路径
                .logoutSuccessUrl("/toLogin?logout=true") // 注销成功后跳转登录页
                .invalidateHttpSession(true) // 注销时销毁session
                .clearAuthentication(true) // 清除认证信息
                .permitAll()
                .and()

                // 6. 配置权限不足处理（403页面）
                .exceptionHandling()
                .accessDeniedPage("/403"); // 权限不足时跳转的页面
    }
}
